package com.recursivechaos.gamemaster;

/**
 * GAME MASTER
 * This class handles all the "game logic" as well as the bot. The two need to 
 * be coupled together due to the nature of how the bot gets/sends messages.
 * 
 * @author Andrew Bell
 */
import java.io.BufferedReader;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Random;

import org.jibble.pircbot.Colors;
import org.jibble.pircbot.PircBot;



import com.recursivechaos.calendr.CalendarWorker;
//import com.recursivechaos.calendr.CalendarWorker;
import com.recursivechaos.dicr.RollDAO;
import com.recursivechaos.dicr.RollerDAOImpl;
import com.recursivechaos.gamemaster.classes.CharObj;
import com.recursivechaos.gamemaster.dao.CampaignDAO;
import com.recursivechaos.gamemaster.dao.CharObjDAO;
import com.recursivechaos.gamemaster.dao.GameSettingsDAO;
import com.recursivechaos.gamemaster.dao.MonsterNameDAO;
import com.recursivechaos.gamemaster.dao.RaceObjDAO;
import com.recursivechaos.gamemaster.dao.WeaponObjDAO;
import com.recursivechaos.gamemaster.exception.GameException;

public class GameMasterWorker extends PircBot {
	private CharObjDAO charDAO = new CharObjDAO();
	private CampaignDAO campDAO = new CampaignDAO();
	private WeaponObjDAO weapDAO = new WeaponObjDAO();
	private RaceObjDAO raceDAO = new RaceObjDAO();
	private GameSettingsDAO settDAO = new GameSettingsDAO();

	private int DAD_JOKE_CHANCE = settDAO.getIntSetting("DAD_JOKE_CHANCE");
	private int MONSTER_GENERATION_CHANCE = settDAO
			.getIntSetting("MONSTER_GENERATION_CHANCE");
	CalendarWorker cal = new
	 CalendarWorker(settDAO.getStringSetting("CAL_URL"));
    private String HELP_NUDGE = settDAO.getStringSetting("HELP_NUDGE");

	private String debugServer;
	private String channel;
	
	int resetDay=getToday();
	
	/**
	 * TEST constructor
	 */
	public GameMasterWorker() {
		String name = "testuser";
		setName(name);
	}

	private int getToday() {
		Date date = new Date(); // your date
	    Calendar cal = Calendar.getInstance();
	    cal.setTime(date);
	    return cal.get(Calendar.DAY_OF_MONTH);
	}

	/**
	 * PROD constructor
	 * 
	 * @param name
	 *            name of the bot to be used
	 * @param debugServer
	 *            location of the 'debug' server, where the bot will launch, and
	 *            send debug messages
	 */
	public GameMasterWorker(String name, String debugServer) {
		setName(name);
		this.debugServer = debugServer;
		this.channel = debugServer;
	}

	/**
	 * This method takes the raw data from IRC and creates attackors, and then
	 * sends them off to fight.
	 * 
	 * @param channel
	 *            channel campaign is being played on
	 * @param sender
	 *            the attackor
	 * @param message
	 *            located in the message should be the name of the attackee
	 * @throws GameException
	 *             If a game rule is violated, throws an error
	 */
	private void attack(String channel, String sender, String message)
			throws GameException {
		CharObj attackor = null;
		CharObj attackee = null;
		// check if attackor is registered
		try {
			attackor = charDAO.getChar(sender);
		} catch (GameException e) {
			// Now you are!
			attackor = register(channel, sender, message);
		}
		// check if attackee is registered
		attackee = charDAO.findCharInString(message);
		// check if attackee is conscious
		if (attackee.getConscious() == 0) {
			throw new GameException("The target is unconscious.");
		}
		// check if attackor is conscious
		if (attackor.getConscious() == 0) {
			throw new GameException("You can't attack while unconscious!");
		}
		// Attack Monster
		if (charDAO.isMonster(attackee)) {
			// Process attack
			attackChar(attackor, attackee);
		} else {
			throw new GameException("PvP is not enabled on this server.");
		}
	}

	/**
	 * attackChar will set two CharObjs to fight, and counter-attack if a bot
	 * 
	 * @param attackor
	 *            The character initiating the attack
	 * @param attackee
	 *            The character defending
	 * @throws GameException
	 */
	private void attackChar(CharObj attackor, CharObj attackee)
			throws GameException {
		RollDAO roller = new RollerDAOImpl();
		int baseRoll = roller.rollFromCheckedString("D20");
		int atk = attackor.getRace().getRaceAtk();
		if (attackor.getType().equals("player")) {
			atk = atk + settDAO.getIntSetting("PC_HANDICAP");
		} else {
			atk = atk + settDAO.getIntSetting("MONSTER_HANDICAP");
		}
		int atkRoll = baseRoll + atk;
		int defAC = attackee.getRace().getRaceAc();
		if (attackee.getType().equals("monster")) {
			defAC = defAC + settDAO.getIntSetting("MONSTER_HANDICAP");
		}
		int atkCritMult = 1;
		boolean cAtk = false; // counter-attack
		// Attack Roll
		String result = attackor.getCharName() + " rolled a " + baseRoll;
		if (atk > 0) {
			result += "+" + atk;
		} else if (atk < 0) {
			result += atk;
		}
		result += " with their " + attackor.getWeapon().getWeapType()
				+ " against " + attackee.getCharName() + "'s AC of " + defAC;
		// Attack Success
		if (atkRoll > defAC) {
			// Crit Check
			if (atkRoll >= (attackor.getWeapon().getWeapCritRoll())) {
				atkCritMult = attackor.getWeapon().getWeapCritMult();
				result += " and landed a X"
						+ attackee.getWeapon().getWeapCritMult()
						+ " critical hit";
			}
			RollDAO dmgRoll = new RollerDAOImpl();
			int weapDmg = dmgRoll.rollFromCheckedString(attackor.getWeapon()
					.getWeapDmg());
			if (attackor.getType().equals("player")) {
				weapDmg = weapDmg + settDAO.getIntSetting("PC_HANDICAP");
			}
			int dmg = ((weapDmg) * atkCritMult);
			charDAO.takeDamage(attackee, dmg);
			result += ", for " + dmg + " damage, ";
			// Attack fail
		} else {
			result += ", and missed. ";
		}
		// Attackee result
		if (attackee.getConscious() == 1) {
			result += attackee.getCharName() + " has " + attackee.getCurHp()
					+ " HP.";
			// if attacking a monster, will set a counter attack
			if (charDAO.isMonster(attackee)) {
				cAtk = true;
			}
		} else {
			if (charDAO.isMonster(attackee)) {
				result += "slaying them. ";
				// deletes if unconscious monster
				charDAO.unmake(attackee);
				try {
					charDAO.addKill(attackor);
					result += attackor.getCharName() + " now has "
							+ attackor.getKills() + " kills.";
				} catch (Exception e) {
					sendDebugMessage(e, attackor.getCharName(), "Racked up a "
							+ "kill, but it went uncounted.");
				}
			} else {
				result += "knocking them unconscious. ";
			}
		}
		// Display results
		sendMessage(channel, result);
		// Counter-attack if necessary
		if (cAtk) {
			attackChar(attackee, attackor);
		}
	}

	/**
	 * Creates a 'dad joke' reply given a sentance with the word "i'm" inside
	 * 
	 * @param message
	 *            message from server containing "i'm"
	 */
	private void dadJoke(String message) {
		DAD_JOKE_CHANCE = settDAO.getIntSetting("DAD_JOKE_CHANCE");
		try {
			Random generator = new Random();
			if (DAD_JOKE_CHANCE > 0) {
				int r = generator.nextInt(DAD_JOKE_CHANCE);
				if (r == (DAD_JOKE_CHANCE - 1)) {
					int im = message.indexOf("I'm");
					if (im == -1) {
						im = message.indexOf("i'm");
					}
					im += 4;
					int per = 255;
					// Check for various punctuation.
					if ((message.indexOf(".") < per)
							&& (message.indexOf(".") != -1)) {
						per = message.indexOf(".");
					}
					if ((message.indexOf(",") < per)
							&& (message.indexOf(",") != -1)) {
						per = message.indexOf(",");
					}
					if ((message.indexOf("?") < per)
							&& (message.indexOf("?") != -1)) {
						per = message.indexOf("?");
					}
					if ((message.indexOf("!") < per)
							&& (message.indexOf("!") != -1)) {
						per = message.indexOf("!");
					}
					if ((message.indexOf(" and ") < per)
							&& (message.indexOf(" and ") != -1)) {
						per = message.indexOf(" and ");
					}
					if ((message.indexOf(" or ") < per)
							&& (message.indexOf(" or ") != -1)) {
						per = message.indexOf(" or ");
					}
					String kid = "";
					// If no punctuation found after i'm
					if ((per == 255) || (im > per)) {
						kid = message.substring(im);
					} else {
						kid = message.substring(im, per);
					}
					// remove a/an
					if(kid.substring(0, 2).equals("a ")){
						kid = kid.substring(2);
					}
					if(kid.substring(0,3).equals("an ")){
						kid = kid.substring(3);
					}
					// Long messages will not display, nor will short ones
					if ((kid.length() > 2) && (kid.length() < 50)) {
						sendMessage(channel, "Hi " + kid + ", I'm " + getName()
								+ ".");
					}
				}
			}
		} catch (Exception e) {
			// It's okay, you'd make a terrible dad.
			sendDebugMessage(e, "Tried to be a dad, but I failed");
		}
	}

	/**
	 * Checks message for help, and displays the respective menu.
	 * 
	 * @param sender
	 *            requestor
	 * @param message
	 *            help string, containing additional subcommands
	 */
	private void helpCommands(String sender, String message) {
		message = message.toUpperCase();
		if (message.equalsIgnoreCase("help")) {
			sendMessage(sender, Colors.BOLD + "***** " + getName()
					+ " Help *****");
			sendMessage(sender, "OH GAWD THIS IS SO SLOW, IM SORRY!");
			sendMessage(sender, " ");
			sendMessage(sender, Colors.BOLD + getName() + Colors.NORMAL
					+ " is an RPG playing IRC bot. Most rules are based "
					+ "off of the Pathfinder Roleplaying Game,");
			sendMessage(sender,
					"with some liberties taken. You can find out more at "
							+ "https://code.google.com/p/irc-game-master");
			sendMessage(sender, " ");
			sendMessage(sender, "For more information on a command, type:");
			sendMessage(sender, Colors.BOLD + "/msg " + getName()
					+ " help <command>");
			sendMessage(sender, " ");
			sendMessage(sender, Colors.BOLD + "PRIVATE MESSAGE COMMANDS:");
			sendMessage(sender, Colors.BOLD + "INFO      " + Colors.NORMAL
					+ "Displays information on character.");
			sendMessage(sender, Colors.BOLD + "SET       " + Colors.NORMAL
					+ "Sets various player options.");
			sendMessage(sender, " ");
			sendMessage(sender, Colors.BOLD + "CHANNEL COMMANDS:");
			sendMessage(sender, Colors.BOLD + "!ATTACK   " + Colors.NORMAL
					+ "Attacks a designated target.");
			sendMessage(sender, Colors.BOLD + "!REGISTER " + Colors.NORMAL
					+ "Registers your nick with the game.");
			sendMessage(sender, " ");
			sendMessage(sender, Colors.BOLD + "***** End of Help *****");

		}
		// HELP SET
		if (message.equalsIgnoreCase("help set")) {
			sendMessage(sender, Colors.BOLD + "***** " + getName()
					+ " Help *****");
			sendMessage(sender, "Help for " + Colors.BOLD + "SET:");
			sendMessage(sender, " ");
			sendMessage(sender, Colors.BOLD + "SET" + Colors.NORMAL
					+ " allows you to manually change your character.");
			sendMessage(sender, " ");
			sendMessage(sender, "The following subcommands are available:");
			sendMessage(sender, Colors.BOLD + "RACE      " + Colors.NORMAL
					+ "Sets your character race.");
			sendMessage(sender, Colors.BOLD + "WEAPON    " + Colors.NORMAL
					+ "Sets your character weapon.");
			sendMessage(sender, " ");
			sendMessage(sender, "For more information, use " + Colors.BOLD
					+ "/msg " + getName() + " HELP SET <command>");
			sendMessage(sender, Colors.BOLD + "***** End of Help *****");
		}
		// HELP SET WEAPON
		if (message.equalsIgnoreCase("help set weapon")) {
			// TODO split up weapon list, it's too big for IRC to post
			List<String> weapons = null;
			try {
				weapons = weapDAO.getWeaponStringList();
			} catch (Exception e) {
				sendDebugMessage(e, "Could not get weapon list.");
			}
			String weaponString = "";
			for (int i = 0; i < weapons.size(); i++) {
				if (!(i == weapons.size() - 1)) {
					weaponString += (weapons.get(i) + ", ");
				} else {
					weaponString += (weapons.get(i) + ".");
				}
			}
			sendMessage(sender, Colors.BOLD + "***** " + getName()
					+ " Help *****");
			sendMessage(sender, "Help for " + Colors.BOLD + "SET WEAPON:");
			sendMessage(sender, " ");
			sendMessage(sender, Colors.BOLD + "SET WEAPON" + Colors.NORMAL
					+ " changes your currently equipped weapon. ");
			sendMessage(sender, "Weapon stats can be found here:");
			sendMessage(sender, "http://paizo.com/pathfinderRPG/prd/"
					+ "ultimateEquipment/armsAndArmor/weapons.html");
			sendMessage(sender, " ");
			sendMessage(sender, "The following weapons are available:");
			sendMessage(sender, weaponString.toUpperCase());
			sendMessage(sender, " ");
			sendMessage(sender, "Syntax: " + Colors.BOLD
					+ "SET WEAPON <new weapon>");
			sendMessage(sender, " ");
			sendMessage(sender, "Example: " + Colors.BOLD + "/msg " + getName()
					+ " SET WEAPON " + weapons.get(0).toUpperCase());
			sendMessage(sender, Colors.BOLD + "***** End of Help *****");
		}
		// HELP SET RACE
		if (message.equalsIgnoreCase("help set race")) {
			List<String> races = raceDAO.getRaceStringList();
			String raceString = "";
			for (int i = 0; i < races.size(); i++) {
				if (!(i == races.size() - 1)) {
					raceString += (races.get(i) + ", ");
				} else {
					raceString += (races.get(i) + ".");
				}
			}
			sendMessage(sender, Colors.BOLD + "***** " + getName()
					+ " Help *****");
			sendMessage(sender, "Help for " + Colors.BOLD + "SET RACE:");
			sendMessage(sender, " ");
			sendMessage(sender, Colors.BOLD + "SET RACE" + Colors.NORMAL
					+ " thanks to advancements in the world of magic, "
					+ "you can set your race");
			sendMessage(sender,
					"For the sake of gameplay, there have been some changes "
							+ "made to races: http://paizo.com/prd/races.html");
			sendMessage(sender, " ");
			sendMessage(sender, "The following races are available:");
			sendMessage(sender, raceString.toUpperCase());
			sendMessage(sender, " ");
			sendMessage(sender, "Syntax: " + Colors.BOLD
					+ "SET RACE <new race>");
			sendMessage(sender, " ");
			sendMessage(sender, "Example: " + Colors.BOLD + "/msg " + getName()
					+ " SET RACE " + races.get(0).toUpperCase());
			sendMessage(sender, Colors.BOLD + "***** End of Help *****");
		}
		// HELP INFO
		if (message.equals("HELP INFO")) {
			List<String> chars = charDAO.getCharStringList();
			String charString = "";
			for (int i = 0; i < chars.size(); i++) {
				if (!(i == chars.size() - 1)) {
					charString += (chars.get(i) + ", ");
				} else {
					charString += (chars.get(i) + ".");
				}
			}
			sendMessage(sender, Colors.BOLD + "***** " + getName()
					+ " Help *****");
			sendMessage(sender, "Help for " + Colors.BOLD + "INFO:");
			sendMessage(sender, " ");
			sendMessage(sender, Colors.BOLD + "INFO" + Colors.NORMAL
					+ " returns stats about any character in the game.");
			sendMessage(sender, "If no character found, "
					+ "assumes that you want to hear about yourself.");
			sendMessage(sender, " ");
			sendMessage(sender, "The following characters are playing:");
			sendMessage(sender, charString.toUpperCase());
			sendMessage(sender, " ");
			sendMessage(sender, "Syntax: " + Colors.BOLD + "INFO <character>");
			sendMessage(sender, " ");
			sendMessage(sender, "Example: " + Colors.BOLD + "/msg " + getName()
					+ " INFO " + chars.get(0).toUpperCase());
			sendMessage(sender, Colors.BOLD + "***** End of Help *****");
		}

	}

	/**
	 * On action, such as /me userFoo hits irc-game-master with a trout
	 */
	@Override
	public void onAction(String sender, String login, String hostname,
			String target, String action) {
		// Checks to see if a monster is preset, otherwise just returns an ok
		if (action.contains("looks at " + getName())) {

			try {
				flushSettings();
				if (charDAO.isMonsterPresent(channel)) {
					try{
						sendMessage(channel, "I still see " + Colors.RED + monsterList());
					} catch (Exception e) {
						sendMessage(channel, "I lost track of the monsters.");
						sendDebugMessage(e,"I lost track of the monsters :( ");
					}
				} else {
					sendAction(target, " looks back. Longingly.");
				}
			} catch (GameException e) {
				sendMessage(channel,"I feel dead on the inside.");
				sendDebugMessage(e, sender, "mySQL connection has failed.");
			}
		}
	}

	private String monsterList() throws GameException {
		List<String> monList = charDAO.getMonsterStringList();
		String monStr = "";
		for (int i = 0; i < monList.size(); i++) {
			monStr += monList.get(i);
			if (monList.size() != 1
					|| ((monList.size() != 1 && (i != monList
							.size() - 1)))) {
				monStr += ",";
			}
		}
		return monStr;
	}

	/**
	 * On Message Event - regular chat message events
	 */
	@Override
	public void onMessage(String channel, String sender, String login,
			String hostname, String message) {
		this.channel = channel;
		channel = channel.toLowerCase();

		// REGISTER
		if (message.startsWith("!register")) {
			try {
				register(channel, sender, message);
			} catch (GameException e) {
				sendMessage(sender, e.getMessage());
				sendDebugMessage(e, sender, message);
			}
		}

		// ATTACK
		if (message.startsWith("!attack")) {
			// TODO It seems to be throwing an exception when the player has
			// extra text appended, but attack still happens.
			try {
				attack(channel, sender, message);
			} catch (GameException e) {
				sendMessage(sender, e.getMessage());
				sendDebugMessage(e, sender, message);
			}
		}

		// RANDOM MONSTERS
		try {
			randomMonsterGenerator();
		} catch (Exception e) {
			sendDebugMessage(e, "Monster generator tried, but failed.");
		}

		// MEETUPS
		/**
		 * Meetup request - Fetches the 5 upcoming events from a public calendar
		 * feed url, and messages the channel and the user.
		 */
		 if (message.startsWith("!meetup")) {
		 try {
		 // Get list of meetups
		 String[] meetupList = cal.getMeetupTicker();
		 // Display "header" messages
		 sendMessage(sender, "The next 5 meetups are: ");
		 sendMessage(channel, "Next Meetup: " + meetupList[0]
		 + ". Check your messages for more.");
		 // Sends message of all meetups
		 for (int i = 0; i < 5; i++) {
		 sendMessage(sender, meetupList[i]);
		 }
		 } catch (Exception e) {
		 sendMessage(channel,
		 "I've seem to have misplaced my calendar...");
		 }
		 }
		// FUN STUFF
		// DAD JOKES
		if (message.toLowerCase().contains("i'm")) {
			dadJoke(message);
		}

		// Catfacts
		if (message.startsWith("!catfact")) {
			try {
				BufferedReader br = new BufferedReader(new FileReader(
						"catfacts.txt"));
				List<String> catfacts = new ArrayList<String>();
				String line = null;
				while ((line = br.readLine()) != null) {
					catfacts.add(line);
				}
				Random randomGenerator = new Random();
				sendMessage(channel,
						catfacts.get(randomGenerator.nextInt(catfacts.size())));
				br.close();
			} catch (Exception e) {
				sendMessage(channel, "I've lost my cat facts!");
			}
		}
	}

	/**
	 * On private message event
	 */
	@Override
	public void onPrivateMessage(String sender, String login, String hostname,
			String message) {
		// TODO send messages as bot

		// HELP COMMANDS
		helpCommands(sender, message);

		// REGULAR COMMANDS
		// INFO
		if (message.toUpperCase().startsWith("INFO")) {
			try {
				sendMessage(sender, status(charDAO.findCharInString(message)));
			} catch (GameException e) {
				try {
					sendMessage(sender, status(sender));
				} catch (GameException e1) {
					sendMessage(sender, "Unable to lookup info for that user.");
					sendDebugMessage(e, sender, message);
				}
			}
		}
		// WEAPON
		if (message.toUpperCase().startsWith("SET WEAPON")) {
			try {
				CharObj thisChar = charDAO.getChar(sender);
				charDAO.setWeapon(thisChar, message);
				CharObj updatedChar = charDAO.getChar(sender);
				sendMessage(sender, "You are now wielding a "
						+ updatedChar.getWeapon().getWeapType());
			} catch (Exception e) {
				sendMessage(sender, "You were not able to change weapons. "
						+ "Make sure your weapon exists.");
				sendDebugMessage(e, sender, message);
			}
		}
		// RACE
		if (message.toUpperCase().startsWith("SET RACE")) {
			try {
				CharObj thisChar = charDAO.getChar(sender);
				charDAO.setRace(thisChar, message);
				CharObj updatedChar = charDAO.getChar(sender);
				sendMessage(sender, "You are now a "
						+ updatedChar.getRace().getRaceName());
			} catch (Exception e) {
				sendMessage(sender, "You were not able to change races. "
						+ "Make sure your race exists.");
				sendDebugMessage(e, sender, message);
			}
		}
		// GM COMMANDS
		if (message.toUpperCase().startsWith("PARTYREST")) {
			if (charDAO.isGM(sender)) {
				try {
					partyRest();
					sendMessage(channel, "The party has rested.");
				} catch (Exception e) {
					sendMessage(sender, "The party was not able to rest.");
					sendDebugMessage(e, sender, message);
				}
			}
		}
		// JOIN
		if (message.toUpperCase().startsWith("JOIN")) {
			if (charDAO.isGM(sender)) {
				// finds the channel name
				channel = message.substring(message.indexOf("#"));
				joinChannel(channel);
			}
		}
		// SPAWNMONSTER
		if (message.toUpperCase().startsWith("SPAWNMONSTER")) {
			if (charDAO.isGM(sender)) {
				spawnMonster();
			}
		}
		// RELOAD SETTINGS
		if (message.toUpperCase().startsWith("FLUSHSETTINGS")) {
			if (charDAO.isGM(sender)) {
				try {
					sendMessage(sender, flushSettings());
				} catch (Exception e) {
					sendDebugMessage(e, "Could not flush settings.");
				}
			}
		}
		// SEND MESSAGE
		if (message.toUpperCase().startsWith("SENDMESSAGE")){
			if (charDAO.isGM(sender)){
				sendMessage(channel, message.substring(message.indexOf(" ")));
			}
		}
	}

	private String flushSettings() {
		DAD_JOKE_CHANCE = settDAO.getIntSetting("DAD_JOKE_CHANCE");
		MONSTER_GENERATION_CHANCE = settDAO
				.getIntSetting("MONSTER_GENERATION_CHANCE");
		// cal = new
		// CalendarWorker(settDAO.getStringSetting("CAL_URL"));
		HELP_NUDGE = settDAO.getStringSetting("HELP_NUDGE");
		String resp = "DAD_JOKE: " + DAD_JOKE_CHANCE + " MONSTER: "
				+ MONSTER_GENERATION_CHANCE
				+ " SETTINGS HAVE BEEN UPDATED.";
		return resp;
	}

	/**
	 * Both heals, and restores consciousness of all PCs
	 * 
	 * @throws GameException
	 */
	private void partyRest() throws GameException {
		campDAO.partyRest();
		campDAO.partyRevive();

	}
	
	@Override
	protected void onServerPing(String message){
		super.onServerPing(message.substring(5));
		flushSettings();
		if((resetDay<getToday())||(getToday()==1&&resetDay>1)){
			try {
				partyRest();
				resetDay = getToday();
				sendMessage(channel, "The party has rested.");
			} catch (GameException e) {
				sendDebugMessage(e,"Was not able to auto-rest.");
			}
			
		}
	}

	/**
	 * Will create a random monster given MONSTER_GENERATION_CHANCE and
	 * announces it to the channel.
	 */
	private void randomMonsterGenerator() {
		Random generator = new Random();
		int r = generator.nextInt(MONSTER_GENERATION_CHANCE);
		if ((r == (MONSTER_GENERATION_CHANCE - 1))
				&& (MONSTER_GENERATION_CHANCE != 0)) {
			MONSTER_GENERATION_CHANCE = settDAO
					.getIntSetting("MONSTER_GENERATION_CHANCE");
			try {
				if (!charDAO.isMonsterPresent(channel)) {
					spawnMonster();
				}
			} catch (GameException e) {
				sendDebugMessage(e, "Could not check for monsters.");
			}
		}

	}

	/**
	 * Creates a character based on input from the user, or will generate a
	 * random character
	 * 
	 * @param channel
	 *            Channel the game is ran in
	 * @param sender
	 *            Nick of the user, will become character name
	 * @param input
	 *            Input string, place race and weapon in here
	 * @return returns the new CharObj
	 * @throws GameException
	 *             Error creating the new character
	 */
	private CharObj register(String channel, String sender, String input)
			throws GameException {
		if (charDAO.isRegistered(sender)) {
			throw new GameException("You are already registered, "
					+ "you silly goose.");
		}
		CharObj regChar = charDAO.registerChar(channel.toLowerCase(), sender,
				input);
		sendMessage(regChar.getCharName(),
				"You join the party as a " + regChar.getRace().getRaceName()
						+ " wielding a " + regChar.getWeapon().getWeapType()
						+ " with " + regChar.getCurHp() + " HP. " + HELP_NUDGE);
		sendMessage(channel, regChar.getCharName() + ", the "
				+ regChar.getWeapon().getWeapType() + " wielding "
				+ regChar.getRace().getRaceName() + ", joined the party.");
		return regChar;
	}

	/**
	 * Sends generic debug messages for when a sender has not initiated the
	 * request that generated an exception
	 * 
	 * @param string
	 *            Text to be displayed with the error
	 * @param e
	 *            Exception thrown
	 */
	private void sendDebugMessage(Exception e, String string) {
		sendMessage(debugServer, "ERROR: " + e.getMessage());
	}

	/**
	 * Sends a message to the debug (starting) channel, including the exception,
	 * the sender, and their input
	 * 
	 * @param e
	 *            Exception
	 * @param sender
	 *            Who attempted the action
	 * @param message
	 *            Their input string
	 */
	private void sendDebugMessage(Exception e, String sender, String message) {
		sendMessage(debugServer, "DEBUG: User: " + sender + " Sent the line: "
				+ message + " And failed: " + e.getMessage());
	}

	/**
	 * TESTING - receives a line from the test interface to test commands
	 * 
	 * @param message   line sent to be tested
	 */
	public void sendLine(String message) {
		String channel = "#NotIRC";
		String sender = "TestUser";
		if (message.startsWith("!register")) {
			try {
				register(channel, sender, message);
			} catch (GameException e) {
				e.printStackTrace();
			}
		}
		if (message.startsWith("!randomname")) {
			MonsterNameDAO mName = new MonsterNameDAO();
			System.out.println(mName.getRandomName());
		}
	}

	/**
	 * Creates a random monster, and announces it to the channel
	 */
	private void spawnMonster() {
		try {
			CharObj monster = charDAO.spawnRandomMonster(channel);
			String[] mad = { "foolish", "frantic", "frenzied", "psychotic",
					"trollish", "daft", "foolheardy", "ludicrous", "wacky",
					"agitated", "frantic", "furious", "livid", "berserk",
					"wild", "raging", "wrathful", "cross", "corrupt",
					"hateful", "heinous", "nefarious", "unpleasant", "vile",
					"baneful", "depraved" };
			Random generator = new Random();
			String stat = mad[generator.nextInt(25)];
			if (startsWithVowel(stat)) {
				stat = "An " + stat;
			} else {
				stat = "A " + stat;
			}
			sendMessage(channel,
					stat + " " + monster.getRace().getRaceName() + " named "
							+ Colors.RED + Colors.BOLD + monster.getCharName()
							+ Colors.NORMAL + " has appeared!");
		} catch (GameException e) {
			sendDebugMessage(e, "Could not generate monster.");
		}

	}

	/**
	 * Returns true if starting character is a vowel, for parsing sentances
	 * 
	 * @param stat
	 *            String to check
	 * @return True if starting with a vowel
	 */
	private boolean startsWithVowel(String stat) {
		boolean startVowel = false;
		List<String> vowels = Arrays.asList("a", "e", "i", "o", "u", "y");
		String firstChar = stat.substring(0, 1);
		for (int i = 0; i < vowels.size(); i++) {
			if (firstChar.equals(vowels.get(i))) {
				startVowel = true;
			}
		}
		return startVowel;
	}

	/**
	 * Returns a string of the status of the requested char
	 * 
	 * @param statusChar
	 *            character to fetch status of
	 * @return String status
	 */
	private String status(CharObj statusChar) {
		return (statusChar.getCharName() + " is a "
				+ statusChar.getRace().getRaceName() + " with a "
				+ statusChar.getWeapon().getWeapType() + ", "
				+ statusChar.getCurHp() + " HP, and " + +statusChar.getKills() + " kills.");

	}

	/**
	 * Returns a string detailing the status of the user
	 * 
	 * @param sender
	 *            user requesting the status
	 * @return String
	 * @throws GameException
	 */
	private String status(String sender) throws GameException {
		CharObj statusChar = charDAO.getChar(sender);
		return status(statusChar);
	}
}
